﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#pragma once

#include "WeakPtr.h"
#include "IPickPointAction.h"
#include "ILineEditEventHandler.h"

namespace gcmp
{
    class IGraphicsNodeReference;
    class ISnap;
    class PickFilter;
    class ISnapCandidates;
    class ISnapContext;
    class IPickPointActionConfig;
    class IPickFilter;
    class Vector3d;
    class IActionCoordinateInputWidget;
    class ICoordinateInputDefinition;
    class ILineEditEventArgs;
    class IUiViewMouseEventHandler;
}

namespace Sample
{
    class SamplePickPointAction : public gcmp::IPickPointAction, public gcmp::ILineEditEventHandler
    { 
    public:
        SamplePickPointAction(gcmp::PickPointExchangeData &exchangeData, gcmp::IPickPointAction::MoveCallback moveCallback = nullptr,
            gcmp::ActionFinishedMode enActionFinishedMode = gcmp::ActionFinishedMode::LButtonDown, bool isReturnKeyNeedCanceled = false, 
            gcmp::OwnerPtr<gcmp::IPickPointActionConfig> opPickConfig = nullptr);
        virtual ~SamplePickPointAction();

        // IAction接口实现
    public:
        virtual void ActionCancelled() override;
        virtual void InitAction(gcmp::IUiView* pCurrentView) override;
        virtual gcmp::OwnerPtr<gcmp::IMenuItemContainerDefinition> PrepareContextMenu(gcmp::IUiView* pUIView) override;
        virtual bool OnLButtonDown(gcmp::IUiView* pCurrentView,const gcmp::Vector3d& pos) override;
        virtual bool OnLButtonUp(gcmp::IUiView* pCurrentView,const gcmp::Vector3d& pos) override;
        virtual bool OnRButtonDown(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnRButtonUp(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos) override;
        virtual bool OnMovePoint(gcmp::IUiView* pCurrentView,const gcmp::Vector3d& pos) override;
        virtual bool OnKeyDown(gcmp::IUiView* pCurrentView, int nChar) override;
        virtual bool OnKeyUp(gcmp::IUiView* pCurrentView, int nChar) override;

        virtual bool OnReceiveViewInputData(gcmp::IUiView* pCurrentView, const gcmp::ActionViewInput& inputParam) override;
        virtual bool OnMoveCallback(gcmp::IUiView* pCurrentView) override;
        virtual void OnChildActionFinished(gcmp::IUiView* pCurrentView, const gcmp::ActionOutput& childActionReturnParam) override;

        virtual bool RegisterEditCallBack(gcmp::IPickPointAction::EditCallback &editCallback) override;

    public:
        virtual bool IsCaught() const override;

        virtual gcmp::ISnapContext* GetSnapContext() const override;
        virtual bool SetSnapContext(const gcmp::ISnapContext* snapContext) override;
        virtual bool SetPickTolarenceBeforeSnapConcretePoint(int pixelCount) override { m_pixelCount = pixelCount; return true; }

        virtual bool SetFirstPoint(const gcmp::Vector3d& firstPoint) override;
        virtual void GetActionOutput(gcmp::ActionOutput& param) const override;

        virtual bool StartCoordinateInput(gcmp::OwnerPtr<gcmp::IPlane> opWorkPlane = nullptr, bool userCustomInput = false) override;
        
        virtual std::wstring GetCursorPath() const override final;
        virtual bool SetCursorPathCallBack(gcmp::IPickPointAction::CursorPathCallBack callBack) override final;

        bool SetMoveBeforeSnapCallBack(gcmp::IPickPointAction::MoveBeforeSnapCallBack callback) override { m_moveBeforeSnapCallBack = callback; return true; }
        virtual bool SetFilterSnapTypeForTabKeySwitch(std::vector<gcmp::SnapType> needFilterSnapType) override
        {
            m_filterSnapTypeForTabKeySwitch = needFilterSnapType;
            return true;
        }

    public:
        /// \brief 创建IPickPointAction对象
        ///
        /// \param exchangeData    IPickPointAction的通信结构体
        /// \param moveCallback  回调函数
        /// \param enActionFinishedMode   action结束方式
        /// \param isReturnKeyNeedCanceled   设置用户按了Enter和Retrun键是否退出，缺省不退出
        /// \param opPickConfig   用户可以通过这个接口配置一些用户定制的行为（如：配置拾取时的正交模式）
        static gcmp::OwnerPtr<gcmp::IPickPointAction> Create(gcmp::PickPointExchangeData &exchangeData, gcmp::IPickPointAction::MoveCallback moveCallback = nullptr,
            gcmp::ActionFinishedMode enActionFinishedMode = gcmp::ActionFinishedMode::LButtonDown, bool isReturnKeyNeedCanceled = false, 
            gcmp::OwnerPtr<gcmp::IPickPointActionConfig> opPickConfig = nullptr);


    protected:
        void CalculateReturnResult(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos);
        virtual void On(gcmp::ILineEditEventArgs* pArgs) override;

        virtual bool SetOnKeyDownCallback(OnKeyDownCallback callback) override;

    private:
        //在捕捉中做拾取（默认只有辅助对象，且绑定有调用者指定的命令才会被拾取到)
        void DoPick(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos);
        void DoSnap(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pos);

        //清理捕捉信息(包括返回给用户的和缓存的捕捉状态)
        void ClearSnap();

        void SetUserCustomInput();

        // 获得屏幕点在当前视图平面上的投影点
        bool ProjectPositionOnSnapPlane(const gcmp::Vector3d& pos, gcmp::Vector3d& projectedPos) const;
        bool ProjectPositionOnSnapPlane(const gcmp::Vector3d& pos, gcmp::Vector3d& projectedPos, gcmp::ISnapContext* pSnapContext, const gcmp::IUiView* pCurrentView) const;

        //是否禁用拾取
        bool IsPickVisible();

    private:
        gcmp::PickPointExchangeData m_pped;
        bool m_isCaught;
        gcmp::IPickPointAction::EditCallback m_editCallback;
        gcmp::IPickPointAction::OnKeyDownCallback m_OnKeyDownCallback;
        gcmp::IPickPointAction::CursorPathCallBack m_cursorPathCallBack;
        gcmp::IPickPointAction::MoveBeforeSnapCallBack m_moveBeforeSnapCallBack;                        // OnMovePoint中执行捕捉前用来执行点选的回调函数
        gcmp::IPickPointAction::MoveCallback m_moveCallback;                                            // OnMovePoint中执行捕捉后的回调函数

        bool m_IsTabReset;
        int m_pixelCount = -1;

        gcmp::ActionFinishedMode m_enActionFinishedMode;  //什么情况下结束当前命令

        gcmp::OwnerPtr<gcmp::ISnapCandidates> m_opSnapCandidates;
        gcmp::OwnerPtr<gcmp::ISnapContext> m_opSnapContext;
        gcmp::OwnerPtr<gcmp::IPickPointActionConfig> m_opPickPointActionConfigure;
        gcmp::OwnerPtr<gcmp::IPickFilter> m_oFilterForLocalSnap;
        gcmp::OwnerPtr<gcmp::IPickFilter> m_oFilterForRemoteSnap;
        gcmp::OwnerPtr<gcmp::IActionOutputData> m_opActionOutputData;

        //辅助坐标输入
        // 使用PickPointAction时，当前应该只有一个动态输入对话框
        gcmp::WeakPtr<gcmp::IActionCoordinateInputWidget>  m_opCoordinateInputWidget;
        gcmp::OwnerPtr<gcmp::IPlane>                    m_opWorkPlane;
        gcmp::WeakPtr<gcmp::ICoordinateInputDefinition>  m_wpXCoordEdit;
        gcmp::WeakPtr<gcmp::ICoordinateInputDefinition>  m_wpYCoordEdit;
        gcmp::WeakPtr<gcmp::ICoordinateInputDefinition>  m_wpZCoordEdit;
        gcmp::OwnerPtr<gcmp::IUiViewMouseEventHandler>  m_opViewMouseHandler;
        
        std::vector<gcmp::SnapType> m_filterSnapTypeForTabKeySwitch;

    };
}

